package com.meilai.project.service.personnel.onTurn.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.dto.personnel.onTurn.LeaveOfficeApplyCheckDTO;
import com.meilai.project.dto.personnel.onTurn.LeaveOfficeApplyDTO;
import com.meilai.project.dto.workflow.FlowBusinessDataSuperEntity;
import com.meilai.project.dto.workflow.WorkFlowCheckDTO;
import com.meilai.project.entity.personnel.onTurn.LeaveOfficeApply;
import com.meilai.project.entity.personnel.org.Roster;
import com.meilai.project.entity.system.User;
import com.meilai.project.exception.CommonException;
import com.meilai.project.mapper.personnel.onTurn.LeaveOfficeApplyMapper;
import com.meilai.project.service.personnel.onTurn.LeaveOfficeApplyService;
import com.meilai.project.service.personnel.org.RosterService;
import com.meilai.project.service.system.UserService;
import com.meilai.project.service.system.impl.UserServiceImpl;
import com.meilai.project.util.ThreadLocalUserUtil;
import com.meilai.project.util.WorkFlowUtil;
import com.meilai.project.vo.personnel.onTurn.LeaveOfficeApplyVO;
import com.meilai.project.vo.personnel.org.RosterVO;
import com.meilai.project.vo.system.UserForWFVO;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
@Log4j2
public class LeaveOfficeApplyServiceImpl extends ServiceImpl<LeaveOfficeApplyMapper, LeaveOfficeApply> implements LeaveOfficeApplyService {

    @Autowired
    private RosterService rosterService;
    @Autowired
    private UserService userService;

    @Override
    public Page<LeaveOfficeApplyVO> selectPageList(Integer current_page, Integer page_size, LeaveOfficeApplyDTO searchDTO) {
        Page<LeaveOfficeApplyVO> page = new Page<>(current_page, page_size);
        List<LeaveOfficeApplyVO> list = baseMapper.selectPageList(page, searchDTO);
        return page.setRecords(list);
    }


    @Override
    public LeaveOfficeApplyVO getOneById(Long id) {
        LeaveOfficeApply leaveOfficeApply = getById(id);
        if (leaveOfficeApply == null) throw new CommonException("数据不存在！");

        LeaveOfficeApplyVO vo = baseMapper.selectOneById(id);

        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();
        Boolean canCheck = WorkFlowUtil.canCheckData(userId, leaveOfficeApply);
        vo.setCan_check(canCheck);
        vo.setIs_applyer(userId.equals(leaveOfficeApply.getFlow_applyer_id()));

        List<LeaveOfficeApplyVO> list = new ArrayList<>();
        list.add(vo);

        return CollectionUtils.isNotEmpty(list) ? list.get(0) : null;
    }

    @Override
    @Transactional
    public boolean save(LeaveOfficeApplyDTO dto) {
        // 保存至草稿箱
        int flowResult = saveAndBegin(dto, true);
        if (flowResult != 1) throw new CommonException("保存至草稿箱失败，请联系管理员！");
        else return true;
    }

    @Override
    @Transactional
    public boolean begin(LeaveOfficeApplyDTO dto) {
        // 提交
        int flowResult = saveAndBegin(dto, false);
        if (flowResult == 1) {
            // 仍在流程中
            return true;
        } else if (flowResult == 2) {
            // 无审批节点，直接结束
            return true;
        } else {
            throw new CommonException("提交失败，请联系管理员！");
        }
    }

    @Override
    @Transactional
    public boolean pass(LeaveOfficeApplyCheckDTO dto) {
        // 通过
        int flowResult = passAndBack(dto, true, false);
        if (flowResult == 1) {
            // 通过后仍然在流程中
            return true;
        } else if (flowResult == 2) {
            // 审核后流程结束
            // 保存至花名册
            LeaveOfficeApply ea = getOneById(dto.getId());
            Roster roster = new Roster();
            Long roster_id = ea.getRoster_id();
            roster.setId(roster_id);

            // 禁用用户账号
            Roster roster_1 = rosterService.getById(roster_id);
            User user = new User();
            user.setId(roster_1.getUser_id());
            user.setStatus(0);//禁用
            user.setDeleted_at(LocalDateTime.now());// 删除用户
            userService.updateById(user);

            roster.setLeave_date(LocalDate.now());
            rosterService.updateById(roster);

            return true;
        } else {
            throw new CommonException("通过失败，请联系管理员！");
        }
    }

    @Override
    @Transactional
    public boolean returnBack(LeaveOfficeApplyCheckDTO dto) {
        // 驳回
        int flowResult = passAndBack(dto, false, false);
        if (flowResult != 1) throw new CommonException("驳回失败，请联系管理员！");
        return true;
    }

    @Override
    @Transactional
    public boolean actualDelete(Long id) {
        int flowResult = deleteAndActualDel(id, true);
        if (flowResult != 1) throw new CommonException("彻底删除失败，请联系管理员！");
        return true;
    }


    @Override
    @Transactional
    public boolean delete(Long id) {
        int flowResult = deleteAndActualDel(id, false);
        if (flowResult != 1) throw new CommonException("删除失败，请联系管理员！");
        return true;
    }

    @Override
    public boolean uploadHandoverSheet(String handover_sheet_url, Long leave_office_apply_id) {
        LeaveOfficeApplyVO leaveOfficeApplyVO = baseMapper.selectOneById(leave_office_apply_id);
        Integer flow_status = leaveOfficeApplyVO.getFlow_status();
        if (flow_status != null && flow_status == 4) {
            //更新leave_office_apply的attachment_handover_sheet字段
            LeaveOfficeApply leaveOfficeApply = new LeaveOfficeApply();
            leaveOfficeApply.setId(leave_office_apply_id);
            leaveOfficeApply.setAttachment_handover_sheet(handover_sheet_url);
            updateById(leaveOfficeApply);

            //更新roster的attachment_handover_sheet字段
            Roster roster = new Roster();
            Long roster_id = leaveOfficeApplyVO.getRoster_id();
            roster.setId(roster_id);
            roster.setAttachment_handover_sheet(handover_sheet_url);
            rosterService.updateById(roster);
            return true;
        } else {
            throw new CommonException("保存离职申请单失败！离职申请还未通过");
        }
    }

    @Override
    public List<LeaveOfficeApplyVO> selectOwnList() {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();
        return baseMapper.selectOwnList(userId);
    }

    @Override
    public LeaveOfficeApplyVO getNewAppleyDetail() {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();
        return baseMapper.selectNewAppleyDetail(userId);
    }

    // 保存 和 提交 抽出相同代码
    private int saveAndBegin(LeaveOfficeApplyDTO dto, boolean isSave) {
        // 获取当前人的id和部门id
        UserForWFVO user = UserServiceImpl.getUserForWF(dto);

        //校验当前是否有在流程中离职申请单，已有，不允许再次保存
        RosterVO rosterVO = rosterService.getOneByUserId(user.getUser_id());
        Long rosterId = rosterVO.getId();
        LeaveOfficeApplyVO leaveOfficeApply = baseMapper.getBeginOneByRosterId(rosterId);
        if (leaveOfficeApply != null && leaveOfficeApply.getId() != null) throw new CommonException("保存失败,已存在进行中申请单");

        // 业务数据
        LeaveOfficeApply temp = new LeaveOfficeApply();
        BeanUtils.copyProperties(dto, temp);

        // 设置流程字段，flow_type请自行对应“dict_flow_type”表中的id， 比如当前入职流程（考察登记流程）的id是5
        String flow_title = dto.getName() + "的离职申请"; // 审批流程的名称，需要根据实际业务自行确定
        FlowBusinessDataSuperEntity fbdse = WorkFlowUtil.getStartSuperDataEntity(
                user.getUser_id(),  // 当前用户id
                user.getDep_id(), // 提交的部门id
                10, // 流程类型id，“dict_flow_type”表中的id
                flow_title // 自定义的流程标题
        );
        BeanUtils.copyProperties(fbdse, temp);
        //补充rosterId
        temp.setRoster_id(rosterId);
        // 是否为新数据
        // 新数据时，前端不传业务数据id
        // 非新数据时，即来源是“草稿箱”、“已删除”、“被退回”时，前端需要传入业务数据id
        boolean isFirst = (dto.getId() == null);

        // 由于流程字段含有id，会覆盖数据，此处需要手动setId
        if (!isFirst) temp.setId(dto.getId());

        // 新增或更新业务数据
        boolean flag = isFirst ? save(temp) : updateById(temp);
        if (!flag) throw new CommonException("保存失败");

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<LeaveOfficeApply, LeaveOfficeApplyMapper>(temp.getId(), user.getUser_id(), LeaveOfficeApply.class);

        // 审批流程id
        // 新数据,传0L
        // 非新数据,根据数据id,查找wfData_id
        Long wfData_id = isFirst ? 0L : wfu.getWfDataId(dto.getId());
        // 旧数据记录留存
        LeaveOfficeApply old_data = isFirst ? new LeaveOfficeApply() : temp;

        return isSave ? wfu.SaveDraft(wfData_id) : wfu.Begin(wfData_id, "", old_data);
    }

    // 通过 和 驳回 抽出相同代码
    private int passAndBack(LeaveOfficeApplyCheckDTO dto, boolean isPass, boolean... updateData) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 若业务数据有审批中可修改的内容，请自行更新
        if (updateData != null && updateData[0]) {
            LeaveOfficeApply updateTemp = new LeaveOfficeApply();
            BeanUtils.copyProperties(dto, updateTemp);
            updateById(updateTemp);
        }

        // 业务数据
        LeaveOfficeApply temp = getById(dto.getId());

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<LeaveOfficeApply, LeaveOfficeApplyMapper>(dto.getId(), userId, LeaveOfficeApply.class);

        // 审批入参类
        WorkFlowCheckDTO checkDTO = WorkFlowCheckDTO.getWorkFlowCheckDTO(
                temp.getFlow_current_node_id(), // 当前节点id
                temp.getFlow_json(), // 流程json
                dto.getWf_check_opinion(), // 审批意见
                dto.getWf_check_sign_url(), // 审批签名链接
                JSONObject.toJSONString(temp) // 旧数据留存
        );

        // 审批
        return isPass ? wfu.ToNext(checkDTO) : wfu.ReturnBack(checkDTO);
    }

    // 删除 和 彻底删除 抽出相同代码
    private int deleteAndActualDel(Long id, boolean isActual) {
        // 当前人id
        Long userId = ThreadLocalUserUtil.get().getId();

        // 构造流程工具类
        WorkFlowUtil wfu = new WorkFlowUtil<LeaveOfficeApply, LeaveOfficeApplyMapper>(id, userId, LeaveOfficeApply.class);

        // 流程id
        Long wfData_id = wfu.getWfDataId(id);

        return isActual ? wfu.ActualDelete(wfData_id) : wfu.Delete(wfData_id);
    }


}
